#include "uart_init.h"
#include "readSerial.h"

#include <string.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <unistd.h> //read头文件
#include <stdio.h>  //perror头文件

/**
 * @description: 读取bin文件到缓冲区的函数
 * @return {buffer}  指向存放读取到的内容缓冲
 */
unsigned char* read_bin_file_to_buffer(const char *filename, size_t *buffer_length) {
    FILE *file;
    long file_size;
    unsigned char *buffer;

    // 打开bin文件
    file = fopen(filename, "rb");
    if (file == NULL) {
        perror("Unable to open file");
        return NULL;
    }

    // 获取文件大小
    fseek(file, 0, SEEK_END);
    file_size = ftell(file);
    rewind(file);

    // 动态分配缓冲区
    buffer = (unsigned char *)malloc(file_size);
    if (buffer == NULL) {
        perror("Memory allocation failed");
        fclose(file);
        return NULL;
    }

    // 读取文件内容到缓冲区
    if (fread(buffer, 1, file_size, file) != (size_t)file_size) {
        perror("File read failed");
        free(buffer);
        fclose(file);
        return NULL;
    }

    // 关闭文件
    fclose(file);

    // 设置缓冲区长度
    if (buffer_length != NULL) {
        *buffer_length = (size_t)file_size;
    }

    return buffer;
}

/**
 * @description: 对串口读写
 * @return {*}
 */
int read_serial () 
{
    unsigned char buffer[2] = {0xFF,0xFF}; // 读取串口数据缓冲区
    int count = 2;
    int sendDateLen;

    //FILE *file;
    size_t buffer_length;//缓冲区长度
    size_t buffer_length1 = buffer_length;
    unsigned char *sysbuffer; //指向存放读取到的内容缓冲区

    // 读取bin文件到缓冲区
    sysbuffer = read_bin_file_to_buffer("1.bin", &buffer_length);
        if (sysbuffer == NULL) 
        {
            fprintf(stderr, "Failed to read bin file\n");
            return 1;
        }

    // 打印缓冲区长度
    printf("1.Buffer length: %zu bytes\n", buffer_length); 


    if( (buffer_length %4) ) //下载数据以4对齐，不足部分补0
	{	
		unsigned long FillLen;

		FillLen = 4-(buffer_length%4);		
		memset(&sysbuffer[buffer_length],0,FillLen);
		buffer_length += FillLen; //整理后的长度

	}
        if( (buffer_length %60) ) //下载数据以60对齐，不足部分补f
        {	
            unsigned long FillLen1;

            FillLen1 = 60-(buffer_length%60);		
            memset(&sysbuffer[buffer_length],0xff,FillLen1+120);//多补120个f
            buffer_length += (FillLen1+120); //整理后的长度
        }

    // 打印修改后的缓冲区长度
    printf("after fill Buffer length: %zu bytes\n", buffer_length); 

    int fd = init_serial("/dev/ttyS5",460800);//打开串口并初始化
        if (fd != 0)
        {
            perror("2.open serial");
        }else{
            perror("2.open serial error");
        }


    unsigned char eraseCmd[] = {0x57,0xab,0x81,0x00,0x00,0x00,0x81};//写擦除命令
    int writeErase = write(fd,eraseCmd,7); 
        if (writeErase != 0)
        {
            perror("3.send erase cmd");
        }
    
     usleep(200);

    while (1) 
    {
        ssize_t recvErase = read(fd, buffer, count);
        if (recvErase == 2) 
        {
            if ((buffer[0] == 0x00)&(buffer[1] == 0x00)) //接收到单片机传来的执行成功返回值
            {                 
                perror("  erase has done ");
                break;        
            }               
        }      
    }
    usleep(200);

    
        // tcflush(fd, TCIOFLUSH);   //清空输入输出缓存    
       
        unsigned char promCmd[] = { 0x57,0xab,0x80,0x3C,0X00,0X00,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                    0xEC};//写编程命令

        unsigned char endCmd[] = { 0x57,0xab,0x83,0x3C,0X00,0X00,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                    0xEC};//写终止命令

        unsigned long flashAdder = 0;
        unsigned char promCmdSumCheek = 0;//一帧的校验和
        unsigned char endCmdSumCheek = 0;//最后一帧的校验和
        int flag = 0;
        int text = 0;
        int lastbuffer = 0;
        lastbuffer = (buffer_length%64);
        printf("last date is%d\n",lastbuffer);
        
    next:
        // flashAdder+=60;
        memcpy(promCmd + 6,&sysbuffer[flashAdder],60);//将bin文件中数据放入promcmd中
        flashAdder+=60;
        printf("flashAdder is %zu\n",flashAdder);

        if (120 + buffer_length-flashAdder==0)//当剩余长度等于60时，发送终止命令
        {
        //     promCmd[2] = 0x83;
            flag = 1;
            goto exit;   
        }

        promCmdSumCheek = 0;
        for (int  i = 2; i < 66; i++)//累加算出校验和放至数组末尾
        {
            promCmdSumCheek += promCmd[i];
        }
        promCmd[66] = promCmdSumCheek;

        // int circ = buffer_length/60;

        printf("[5] res2 is %x\n",promCmd[5]);//00
        printf("[6] date is %02x\n",promCmd[6]);//6f
        printf("[7] date is %02x\n",promCmd[7]);//00
        printf("[65] date is %02x\n",promCmd[65]);
        printf(" sumcheek is %x\n",promCmd[66]);
        
        usleep(200);
        tcflush(fd, TCIOFLUSH);   //清空输入输出缓存  
    while (1)
    {        
        // sendDateLen = strlen(promCmd); //strlen 遇到0x00即('\0')停止,导致使用strlen会导致读取不到单片机返回值//可以sendDateLen = sizeof(promCmd);
        sendDateLen = sizeof(promCmd);
        int writeProm = write(fd,promCmd,sendDateLen); 
            if (writeProm == sendDateLen)
            {
                perror("4.send prom cmd");
            }
            else if (writeProm == -1)
            {
                perror("send prom fail");
            }

            while(1)
            {
                usleep(200);
                ssize_t recvProm = read(fd, buffer, count);
                if (recvProm > 0) 
                {
                    if ((buffer[0] == 0x00)&(buffer[1] == 0x00))//接收到单片机传来的执行成功返回值
                    {
                        perror("  prom no err  ");
                        printf("%d\n",text++);
                        goto next;
                        break;        
                    }else if (((buffer[0] == 0x00)&(buffer[1] != 0x01))|flag == 1)
                    {   
                        perror("  prom err  or done ");
                        goto exit;
                    }    
                }      
            }
    } 
    exit:       
    close(fd);
    return 0;
}